﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Xml;

namespace GameVLTK
{
    public abstract class Unit : VisibleGameEntity
    {
        protected int _PrevDirection;

        public int PrevDirection
        {
            get { return _PrevDirection; }
            set
            {
                _PrevDirection = value;
            }
        }

        //Hướng mà nhân vật di chuyển
        protected int _CurrentDirection;

        public int CurrentDirection
        {
            get
            {
                return _CurrentDirection;
            }
            set
            {
                _CurrentDirection = value;
                //Hướng thay đổi phải tính lại dãy frame
                if (_CurrentDirection != _PrevDirection)
                {
                    ReCalcFrameSeq();
                }
            }
        }

        //Số frame của mỗi hướng : Down, Left, Up, Right ...
        protected int[] _FrameOfThatDirs;

        public int[] FrameOfThatDirs
        {
            get
            {
                return _FrameOfThatDirs;
            }
            set
            {
                _FrameOfThatDirs = value;
            }
        }

        //Trạng thái của nhân vật
        protected int _CurrentState;

        public int CurrentState
        {
            get { return _CurrentState; }
            set
            {
                _CurrentState = value;
                //Trạng thái thay đổi phải tính lại dãy frame
                if (this._PrevState != this._CurrentState) //&& this.IsMoving
                {
                    ReCalcFrameSeq();
                }
            }
        }



        protected int _PrevState;
        public int PrevState
        {
            get
            {
                return _PrevState;
            }
            set
            {
                _PrevState = value;
            }
        }

        //Vị trí của Unit trên Mini Map
        protected UnitDot _UnitDot;

        public UnitDot UnitDot
        {
            get { return _UnitDot; }
            set { _UnitDot = value; }
        }

        public Unit()
        {
            this.UnitDot = new UnitDot();

            //Add vào để quản lý các Dot trên Mini Map
            Map.Dots.Add(this.UnitDot);
        }

        //Vận tốc và quãng đường sẽ di chuyển
        protected Vector2 _V;
        protected float _fLen;

       
        /// <summary>
        /// Tính hướng di chuyển dựa vào vị trí hiện tại và vị trí sẽ di chuyển
        /// </summary>
        protected int CalDirection(Vector2 topLeft_B)
        {
            //Tọa độ thực của điểm B
            Vector2 v = topLeft_B;
            Vector2 B = v; //Lưu lại tọa đổ của điểm B

            //== > Tọa độ thực của điểm A
            Vector2 v2 = this.TopLeft;
            Vector2 A = v2; //Lưu lại tọa độ của điểm A

            //Tính vector AB
            v = v - v2;

            //Tính chiều dài vector AB
            this._fLen= v.Length();
            v.Normalize();

            //Tọa độ của vector AC= tọa độ theo hướng hiện tại
            v2 = new Vector2(0f, 1f);

            //v và v2 là 2 unit vector có giá trị nằm trong khoảng [-1, 1]

            //Tính gốc giữa vector AB và AC
            double d = Vector2.Dot(v, v2); //-1 =<d= System.Math.Cos( theta )<=1 ,
            //theta= gốc giữa 2 vector
            //AB và AC.

            double angle = (float)Math.Acos(d); //An angle, θ, measured in radians, such that 0 ≤ θ ≤ π
            //Suy ngược ra giá trị theta= gốc giữa 2 vector
            //AB và AC

            double goc = angle * 180 / MathHelper.Pi;

            //Xác định xem vector AB nằm bên trái hay bên phải vector AC
            // double c = (v.X * v2.Y) - (v.Y * v2.X); 
            double c = (B.X - A.X) * v2.Y - v2.X * (B.Y - A.Y);
            if (c > 0.0)
            {
                goc = 360 - goc;
            }

            //Tính tốc độ di chuyển theo hướng đó
            this._V = (Vector2)(v * Global.CHARACTER_MOVING_SPEED);

            //Tính ra hướng của nhân vật dựa vào gốc quay của nhân vật
            int dir = CalAngle(goc);

            return dir;
        }


        protected int CalAngle(double goc)
        {
            int dir = -1;
            double LENGHT = 22.5;

            if (goc < LENGHT || goc >= 15 * LENGHT)
                dir = 0;
            else if (goc >= LENGHT && goc < 3 * LENGHT)
                dir = 1;
            else if (goc >= 3 * LENGHT && goc < 5 * LENGHT)
                dir = 2;
            else if (goc >= 5 * LENGHT && goc < 7 * LENGHT)
                dir = 3;
            else if (goc >= 7 * LENGHT && goc < 9 * LENGHT)
                dir = 4;
            else if (goc >= 9 * LENGHT && goc < 11 * LENGHT)
                dir = 5;
            else if (goc >= 11 * LENGHT && goc < 13 * LENGHT)
                dir = 6;
            else if (goc >= 13 * LENGHT && goc < 15 * LENGHT)
                dir = 7;

            return dir;

        }

        /// <summary>
        /// Tính toán lại dãy frame và cập nhật lại size cho nhân vật
        /// </summary>
        protected void ReCalcFrameSeq()
        {
            //Tính toán dãy frame
            this.Sprites[this.CurrentState].FrameSequence = this.CalcFrameSeq();

            //Cho biết chỉ số bắt đầu của frame của trạng thái hiện tại
            int beginSeq = this.Sprites[this.CurrentState].FrameSequence[0];

            //Tính toán lại kích thước nhân vật với hướng di chuyển hiện tại
            //Cái này tính bị sai cho kích thước mỗi frame trong dãy frame là hoàn toàn
            //khác nhau.
            this.Size = new Vector2(this.Sprites[this.CurrentState].Textures[beginSeq].Width,
                     this.Sprites[this.CurrentState].Textures[beginSeq].Height);

        }

        /// <summary>
        /// Tính toán dãy frame di chuyển cho trạng thái và hướng hiện tại
        /// </summary>
        /// <returns></returns>
        protected int[] CalcFrameSeq()
        {
            int nFrameOfCurrDir = this._FrameOfThatDirs[this.CurrentState];
            int[] frameSequence = new int[nFrameOfCurrDir];
            int j = 0;
            int lengOfSeqFrameCurrDir = this.CurrentDirection * nFrameOfCurrDir + nFrameOfCurrDir;

            for (int i = this.CurrentDirection * nFrameOfCurrDir; i < lengOfSeqFrameCurrDir; i++)
            {
                frameSequence[j] = i;
                j = j + 1;
            }

            return frameSequence;
        }


    }
}
